from django.db import transaction
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from decimal import Decimal
from apps.accounts.models import User
from apps.master.models import CurrencyRateModel
from apps.project.models import ProjectQuotaModel, ProjectMaintainModel, ProjectDevelopModel, \
    ProjectMaintainAccountModel, ProjectMaintainStageModel, ProjectDevelopAccountModel, ProjectDevelopStageModel, \
    ProjectProcessModel
from apps.projectbases.models import ProjectPlanHModel
from bases.apifields import ApiDecimalField
from bases.serializers import APIModelSerializer
from django.utils import translation
from rest_framework.fields import empty
from apps.codetable.handles import field_codetable

class ProjectQuotaSerializer(APIModelSerializer):
    def __init__(self, instance=None, data=empty, **kwargs):
        super().__init__(instance, data, **kwargs)
        language = translation.get_language()
        self.quote_type_dict = field_codetable('quote_type', localization=language, model='ProjectQuotaModel')

    projectPlanFK = serializers.PrimaryKeyRelatedField(label='项目计划ID', queryset=ProjectPlanHModel.objects.all(), allow_null=True, required=False)
    project_name = serializers.ReadOnlyField(source='projectPlanFK.project_name')
    standard_curr = serializers.ReadOnlyField(source='projectPlanFK.standard_curr') # 标准币种
    quote_no = serializers.CharField(label='报价单号', max_length=10, allow_blank=True, allow_null=True, required=False)
    quote_wfno = serializers.CharField(label='报价WFNO', max_length=10, allow_blank=True, allow_null=True, required=False)
    quote_date = serializers.DateField(label='报价日期', allow_null=True, required=False)
    quote_curr =  serializers.CharField(label='报价币种', max_length=3, allow_blank=True, allow_null=True, required=False)
    quote_content = serializers.CharField(label='报价内容', max_length=50, allow_blank=True, allow_null=True, required=False)
    quote_amount = ApiDecimalField(label='报价金额', allow_null=True, max_digits=18,decimal_places=2, required=False) # 报价金额最多只允许两位小数
    quote_days = ApiDecimalField(label='报价天数', allow_null=True, max_digits=18,decimal_places=1, required=False) # 报价天数最多只允许1位小数
    quote_type = serializers.CharField(label='报价类型', max_length=1, allow_blank=True, allow_null=True, required=False)
    quote_type_desc = serializers.SerializerMethodField()
    receive_date = serializers.DateField(label='受注日', allow_null=True, required=False)
    note = serializers.CharField(label='备注', max_length=255, allow_blank=True, allow_null=True, required=False)
    exchange_rate = serializers.ReadOnlyField()
    rate_amount = serializers.ReadOnlyField()
    is_used = serializers.SerializerMethodField()

    class Meta:
        model = ProjectQuotaModel
        fields = ['id','exchange_rate','rate_amount','projectPlanFK','project_name',
                  'standard_curr','quote_no','quote_wfno','quote_date','quote_curr'
            ,'quote_content','quote_amount','quote_days','quote_type','quote_type_desc','receive_date','note', 'is_used']

    def get_quote_type_desc(self, obj):
        return self.quote_type_dict.get(obj.quote_type) if self.quote_type_dict else obj.quote_type

    def get_is_used(self, obj):
        isMaintainExist = ProjectMaintainModel.objects.filter(quoteFK=obj.id).exists()
        isDevelopExist = ProjectDevelopModel.objects.filter(quoteFK=obj.id).exists()

        if isMaintainExist or isDevelopExist:
            return True
        else:
            return False


    def get_exchange_info(self, obj):
        """
        获取汇率信息，如果在标准币种汇率主表中国不存在，则默认汇率为1
        """
        quote_curr = obj.quote_curr
        quote_amount = obj.quote_amount
        standard_curr = obj.projectPlanFK.standard_curr
        if quote_curr and standard_curr:
            currQuery = CurrencyRateModel.objects.filter(standard_curr=standard_curr, quote_curr=quote_curr).order_by('-rate_date').first()
            if currQuery is not None:
                rate_amount = round(quote_amount/currQuery.exchange_rate, 2)
                return {
                    'exchange_rate': currQuery.exchange_rate,
                    'rate_amount': rate_amount }
            else:
                return {
                    'exchange_rate': 1,
                    'rate_amount': quote_amount }
        else:
            return {
                'exchange_rate': None,
                'rate_amount': None
            }

    def to_representation(self, instance):
        """
        获取序列化后的结果，并对结果进行修改；调用方法get_exchange_info，获取返回的字典，然后拿去字典中的两个字段值
        """
        data = super().to_representation(instance)
        exchange_info = self.get_exchange_info(instance)
        data['exchange_rate'] = exchange_info['exchange_rate'] # 赋给序列化中的只读字段：exchange_rate
        data['rate_amount'] = exchange_info['rate_amount'] # 赋给序列化中的只读字段：rate_amount
        return data

    def validate(self, attrs):
        # 报价金额不允许小于0
        amount = attrs.get('quote_amount')
        if amount <= 0:
            self.handle_validation('quote_amount', '不允许小于等于0')

        # 报价天数，不允许小于0
        days = attrs.get('quote_days')
        if days <= 0:
            self.handle_validation('quote_days', '不允许小于等于0')

        return super().validate(attrs)


class ProjectMaintainSerializer(APIModelSerializer):
    def __init__(self, instance=None, data=empty, **kwargs):
        super().__init__(instance, data, **kwargs)
        language = translation.get_language()
        self.status_dict = field_codetable('project_status', localization=language, model='Project')

    projectPlanFK = serializers.PrimaryKeyRelatedField(label='项目计划ID', queryset=ProjectPlanHModel.objects.all(), allow_null=True, required=False)
    serial_number = serializers.ReadOnlyField(source='projectPlanFK.serialNumberFK.serial_number')
    project_plan_name = serializers.ReadOnlyField(source='projectPlanFK.project_name')
    quoteFK = serializers.PrimaryKeyRelatedField(label='报价单号', queryset=ProjectQuotaModel.objects.all(), allow_null=True,required=False)
    quote_no = serializers.ReadOnlyField(source='quoteFK.quote_no')
    project_name = serializers.CharField(label='项目名称', max_length=50, allow_blank=True, allow_null=True, required=False)
    project_status = serializers.CharField(label='项目状态', max_length=1, allow_blank=True, allow_null=True, required=False)
    project_status_desc = serializers.SerializerMethodField()
    order_no = serializers.CharField(label='订单号', max_length=10, allow_blank=True, allow_null=True, required=False)
    sales_date = serializers.DateField(label='预定销售年月', allow_null=True, required=False)
    sales_amount = ApiDecimalField(label='预定销售金额', allow_null=True, max_digits=18,decimal_places=2, required=False)
    procurement_obj = ApiDecimalField(label='采购管理对象', allow_null=True, max_digits=18,decimal_places=2, required=False)
    procurement_affect = ApiDecimalField(label='采购管理事务', allow_null=True, max_digits=18,decimal_places=2, required=False)
    Maintain_estimates = ApiDecimalField(label='维护预估金额', allow_null=True, max_digits=18,decimal_places=2, required=False)
    quoted_days = ApiDecimalField(label='报价工数（人日）', allow_null=True, max_digits=18,decimal_places=1, required=False)
    quoted_hours = ApiDecimalField(label='报价工数（人时）', allow_null=True, max_digits=18,decimal_places=2, required=False)
    bugdget_hours = ApiDecimalField(label='预算工数（人时）', allow_null=True, max_digits=18,decimal_places=2, required=False)
    reserve_hours = ApiDecimalField(label='预算预备工数（人时）', allow_null=True, max_digits=18,decimal_places=2, required=False)
    note = serializers.CharField(label='备注', max_length=255, allow_blank=True, allow_null=True, required=False)

    class Meta:
        model = ProjectMaintainModel
        fields = '__all__'

    def get_project_status_desc(self, obj):
        return self.status_dict.get(obj.project_status) if self.status_dict else obj.project_status

    def validate(self, attrs):
        projectPlanFK = attrs.get('projectPlanFK')
        sales_date = attrs.get('sales_date')
        sales_amount = attrs.get('sales_amount')
        procurement_obj = attrs.get('procurement_obj')
        procurement_affect = attrs.get('procurement_affect')
        Maintain_estimates = attrs.get('Maintain_estimates')
        quoted_days = attrs.get('quoted_days')
        quoted_hours = attrs.get('quoted_hours')
        bugdget_hours = attrs.get('bugdget_hours')
        reserve_hours = attrs.get('reserve_hours')

        # plan_query = ProjectPlanHModel.objects.get(id=projectPlanFK)
        plan_status = projectPlanFK.project_status
        start_date = projectPlanFK.start_date
        end_date = projectPlanFK.end_date

        if plan_status != 'R':
            raise ValidationError("只有生效状态的项目计划书，才能进行项目维护")
        # 预定销售年月必须处于项目计划书维护期间
        if sales_date < start_date or sales_date > end_date:
            raise ValidationError("预定销售年月必须在项目计划书期间内")
        # 预定销售金额不能小于0
        if sales_amount < 0:
            raise ValidationError("预定销售金额必须大于等于0")
        # 采购管理对象不能小于0
        if procurement_obj < 0:
            raise ValidationError("采购管理对象必须大于等于0")
        # 采购管理事务不能小于0
        if procurement_affect < 0:
            raise ValidationError("采购管理事务必须大于等于0")
        # 维护预估金额不能小于0
        if Maintain_estimates < 0:
            raise ValidationError("维护预估金额必须大于等于0")
        # 报价工数（人日）不能小于0
        if quoted_days < 0:
            raise ValidationError("报价工数（人日）必须大于等于0")
        # 报价工数（人时）不能小于0
        if quoted_hours < 0:
            raise ValidationError("报价工数（人时）必须大于等于0")
        # 预算工数（人时）不能小于0
        if bugdget_hours < 0:
            raise ValidationError("预算工数（人时）必须大于等于0")
        # 预算预备工数（人时）不能小于0
        if  reserve_hours < 0:
            raise ValidationError("预算预备工数（人时）必须大于等于0")

        return super().validate(attrs)


class ProjectDevelopSerializer(APIModelSerializer):
    def __init__(self, instance=None, data=empty, **kwargs):
        super().__init__(instance, data, **kwargs)
        language = translation.get_language()
        self.status_dict = field_codetable('project_status', localization=language, model='Project')

    projectPlanFK = serializers.PrimaryKeyRelatedField(label='项目计划ID', queryset=ProjectPlanHModel.objects.all(), allow_null=True, required=False)
    serial_number = serializers.ReadOnlyField(source='projectPlanFK.serialNumberFK.serial_number')
    project_plan_name = serializers.ReadOnlyField(source='projectPlanFK.project_name')
    quoteFK = serializers.PrimaryKeyRelatedField(label='报价单号', queryset=ProjectQuotaModel.objects.all(), allow_null=True,required=False)
    quote_no = serializers.ReadOnlyField(source='quoteFK.quote_no')
    project_name = serializers.CharField(label='项目名称', max_length=50, allow_blank=True, allow_null=True, required=False)
    project_status = serializers.CharField(label='项目状态', max_length=1, allow_blank=True, allow_null=True, required=False)
    project_status_desc = serializers.SerializerMethodField()
    order_no = serializers.CharField(label='订单号', max_length=10, allow_blank=True, allow_null=True, required=False)
    sales_date = serializers.DateField(label='预定销售年月', allow_null=True, required=False)
    quote_amount = ApiDecimalField(label='报价金额', allow_null=True, max_digits=18,decimal_places=2, required=False)
    sales_amount = ApiDecimalField(label='预定销售金额', allow_null=True, max_digits=18,decimal_places=2, required=False)
    operating_profit = ApiDecimalField(label='营业利润', allow_null=True, max_digits=18,decimal_places=2, required=False)
    operating_margin = ApiDecimalField(label='营业利润率', allow_null=True, max_digits=18,decimal_places=2, required=False)
    reserve_amount = ApiDecimalField(label='预备金额', allow_null=True, max_digits=18,decimal_places=2, required=False)
    quoted_days = ApiDecimalField(label='报价工数（人日）', allow_null=True, max_digits=18,decimal_places=1, required=False)
    quoted_hours = ApiDecimalField(label='报价工数（人时）', allow_null=True, max_digits=18,decimal_places=2, required=False)
    a1bugdget_hours = ApiDecimalField(label='A1预算工数（人时）', allow_null=True, max_digits=18,decimal_places=2, required=False)
    a2manage_hours = ApiDecimalField(label='A2管理工数（人时）', allow_null=True, max_digits=18,decimal_places=2, required=False)
    a3risk_hours = ApiDecimalField(label='A3风险预备工数（人时）', allow_null=True, max_digits=18,decimal_places=2, required=False)
    note = serializers.CharField(label='备注', max_length=255, allow_blank=True, allow_null=True, required=False)

    class Meta:
        model = ProjectDevelopModel
        fields = '__all__'

    def get_project_status_desc(self, obj):
        return self.status_dict.get(obj.project_status) if self.status_dict else obj.project_status

    def validate(self, attrs):
        projectPlanFK = attrs.get('projectPlanFK')
        sales_date = attrs.get('sales_date')
        quote_amount = attrs.get('quote_amount')
        sales_amount = attrs.get('sales_amount')
        operating_profit = attrs.get('operating_profit')
        operating_margin = attrs.get('operating_margin')
        reserve_amount = attrs.get('reserve_amount')
        quoted_days = attrs.get('quoted_days')
        quoted_hours = attrs.get('quoted_hours')
        a1bugdget_hours = attrs.get('a1bugdget_hours')
        a2manage_hours = attrs.get('a2manage_hours')
        a3risk_hours = attrs.get('a3risk_hours')

        plan_status = projectPlanFK.project_status
        start_date = projectPlanFK.start_date
        end_date = projectPlanFK.end_date

        # 只有项目计划书处于生效状态，才能进行项目维护
        if plan_status != 'R':
            raise ValidationError("只有生效状态的项目计划书，才能进行项目维护")
        # 预定销售年月必须处于项目计划书维护期间
        if sales_date < start_date or sales_date > end_date:
            raise ValidationError("预定销售年月必须在项目计划书期间内")
        # 报价金额不能小于0
        if quote_amount < 0:
            raise ValidationError("报价金额必须大于等于0")
        # 预定销售金额不能小于0
        if sales_amount < 0:
            raise ValidationError("预定销售金额必须大于等于0")
        # 营业利润不能小于0
        if operating_profit < 0:
            raise ValidationError("营业利润必须大于等于0")
        # 营业利润率不能小于0
        if operating_margin < 0:
            raise ValidationError("营业利润率必须大于等于0")
        # 预备金额不能小于0
        if reserve_amount < 0:
            raise ValidationError("预备金额必须大于等于0")
        # 报价工数（人日）不能小于0
        if quoted_days < 0:
            raise ValidationError("报价工数（人日）必须大于等于0")
        # 报价工数（人时）不能小于0
        if quoted_hours < 0:
            raise ValidationError("报价工数（人时）必须大于等于0")
        # A1预算工数不能小于0
        if a1bugdget_hours < 0:
            raise ValidationError("A1预算工数（人日）必须大于等于0")
        # A2管理工数（人时）不能小于0
        if a2manage_hours < 0:
            raise ValidationError("A2管理工数（人时）必须大于等于0")
        # A3风险预备工数（人时）不能小于0
        if a3risk_hours < 0:
            raise ValidationError("A3风险预备工数（人时）必须大于等于0")
        # A1+A2+A3 <= quoted_hours * 0.8
        if a1bugdget_hours + a2manage_hours + a3risk_hours > quoted_hours * Decimal(0.8):
            raise ValidationError("A1+A2+A3必须小于等于：报价工时*0.8")

        return super().validate(attrs)

class ProjectMaintainAccountSerializer(APIModelSerializer):
    projectMaintainFK = serializers.PrimaryKeyRelatedField(label='开发项目ID',
                                                          queryset=ProjectMaintainModel.objects.all(),allow_null=True, required=False)
    sales_date = serializers.DateField(label='预定销售年月', allow_null=True, required=False)
    sales_amount = ApiDecimalField(label='营业额', allow_null=True, max_digits=18, decimal_places=2, required=False)
    amount = ApiDecimalField(label='当前耗费', allow_null=True, max_digits=18, decimal_places=2, required=False)
    profit_loss = ApiDecimalField(label='损益', allow_null=True, max_digits=18, decimal_places=2, required=False)

    class Meta:
        model = ProjectMaintainAccountModel
        fields = '__all__'


class ProjectMaintainStageSerializer(APIModelSerializer):
    projectMaintainFK = serializers.PrimaryKeyRelatedField(label='开发项目ID',
                                                           queryset=ProjectMaintainModel.objects.all(), allow_null=True,
                                                           required=False)
    quoted_hours = ApiDecimalField(label='报价工数', allow_null=True, max_digits=18, decimal_places=2, required=False)
    bugdget_hours = ApiDecimalField(label='预算工数', allow_null=True, max_digits=18, decimal_places=2, required=False)
    actual_hours = ApiDecimalField(label='实绩工数', allow_null=True, max_digits=18, decimal_places=2, required=False)
    margin_hours = ApiDecimalField(label='工数计划差', allow_null=True, max_digits=18, decimal_places=2, required=False)

    class Meta:
        model = ProjectMaintainStageModel
        fields = '__all__'

class ProjectDevelopAccountSerializer(APIModelSerializer):
    projectDevelopFK = serializers.PrimaryKeyRelatedField(label='开发项目ID', queryset=ProjectDevelopModel.objects.all(),
                                                       allow_null=True, required=False)
    sales_date = serializers.DateField(label='预定销售年月', allow_null=True, required=False)
    sales_amount = ApiDecimalField(label='营业额', allow_null=True, max_digits=18, decimal_places=2, required=False)
    amount = ApiDecimalField(label='当前耗费', allow_null=True, max_digits=18, decimal_places=2, required=False)
    profit_loss = ApiDecimalField(label='损益', allow_null=True, max_digits=18, decimal_places=2, required=False)

    class Meta:
        model = ProjectDevelopAccountModel
        fields = '__all__'


class ProjectDevelopStageSerializer(APIModelSerializer):
    projectDevelopFK = serializers.PrimaryKeyRelatedField(label='开发项目ID',
                                                          queryset=ProjectDevelopModel.objects.all(),
                                                          allow_null=True, required=False)
    sales_date = serializers.DateField(label='预定销售年月', allow_null=True, required=False)
    quoted_hours = ApiDecimalField(label='报价工数', allow_null=True, max_digits=18, decimal_places=2, required=False)
    bugdget_hours = ApiDecimalField(label='预算工数', allow_null=True, max_digits=18, decimal_places=2, required=False)
    actual_hours = ApiDecimalField(label='实绩工数', allow_null=True, max_digits=18, decimal_places=2, required=False)
    margin_hours = ApiDecimalField(label='工数计划差', allow_null=True, max_digits=18, decimal_places=2, required=False)

    class Meta:
        model = ProjectDevelopStageModel
        fields = '__all__'


class ProjectProcessSerializer(APIModelSerializer):
    recorder = serializers.PrimaryKeyRelatedField(label='记录者外键', queryset=User.objects.all(), allow_null=True, required=False)
    user_name = serializers.ReadOnlyField(source='recorder.name')

    class Meta:
        model = ProjectProcessModel
        fields = '__all__'


class ProjectCombineAccountSerializer(serializers.Serializer):
    """用于将维护项目、开发项目的：阶段别预实管理合并在一起"""
    sales_date = serializers.DateField()
    sales_amount = ApiDecimalField(max_digits=18, decimal_places=6)
    amount = ApiDecimalField(max_digits=18, decimal_places=6)
    profit_loss = ApiDecimalField(max_digits=18, decimal_places=6)
    note = serializers.CharField(max_length=255, allow_blank=True)

    class Meta:
        model = ProjectDevelopAccountModel
        fields = '__all__'


class ProjectCombineStageSerializer(serializers.Serializer):
    """用于将维护项目、开发项目的：项目核算履历合并在一起"""
    sales_date = serializers.DateField()
    quoted_hours = ApiDecimalField(max_digits=18, decimal_places=6)
    bugdget_hours = ApiDecimalField(max_digits=18, decimal_places=6)
    actual_hours = ApiDecimalField(max_digits=18, decimal_places=6)
    margin_hours = ApiDecimalField(max_digits=18, decimal_places=6)
    note = serializers.CharField(max_length=255, allow_blank=True)

    class Meta:
        model = ProjectDevelopStageModel
        fields = '__all__'
